// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

/*
 * @Author: qiulin_JXGM ql1746365080@gmail.com
 * @Date: 2024-10-16 09:35:57
 * @LastEditors: qiulin 1746365080@qq.com
 * @LastEditTime: 2024-12-23 15:10:42
 * @FilePath: \SGFEM\Import\BDFImport\BulkData\Material\MAT1Parser.cpp
 */
#include "Import/BDFImport/BulkData/Material/MAT1Parser.h"

#include <algorithm>
#include <cstdint>
#include <iostream>

#include "Utility/Logging/SGLogger.h"

#include "DBManager/DBServiceFactory.h"
#include "DBManager/IService/Input/Material/IIsotropicMaterialService.h"

#include "Import/BDFImport/BDFParserBase.h"

BULKDATA_ENTRY_PARSER_REG (MAT1);

using namespace SG::DBManager;
using namespace SG::Import;
using namespace SG::DataStructure;

/*
// file://./../../Doc/MarkDown/BulkData/MAT1/MAT1.md>
*/
// 以下需要修改
enum MAT1key : std::uint8_t
{
    MAT1KEY_MID  = 2,
    MAT1KEY_E    = 3,
    MAT1KEY_G    = 4,
    MAT1KEY_NU   = 5,
    MAT1KEY_RHO  = 6,
    MAT1KEY_A    = 7,
    MAT1KEY_TREF = 8,
    MAT1KEY_GE   = 9,   // Structural element damping coefficient. See Remarks  8. ,  9. , and  4. (Real)
    MAT1KEY_ST   = 12,  // Stress limits for tension, compression, and shear are optionally supplied, used only
                        // to compute margins of safety in certain elements; and have no effect on the
                        // computational procedures. (Real > 0.0 or blank). See Remark  14.
    MAT1KEY_SC    = 13,
    MAT1KEY_SS    = 14,
    MAT1KEY_MCSID = 15,
};
enum WhichEnpty : std::uint8_t
{
    NO_EMPTY = 0b0,     // All values present (none are empty)
    E_EMPTY  = 0b10,    // E is empty
    U_EMPTY  = 0b100,   // NU is empty
    G_EMPTY  = 0b1000,  // G is empty
    EU_EMPTY = 0b0110,  // Both E and NU are empty
    GU_EMPTY = 0b1100,  // Both G and NU are empty
};

Common::Status BDF::BULKDATA::ParseMAT1 (const std::shared_ptr<SG::DBManager::DBServiceFactory>& dbServiceFactory,
                                         std::vector<std::string>&                               dividedEntryInfo)
{
    // 创建一个用于保存MAT1材料数据的临时结构体对象
    FEM::IsotropicMaterial tempMAT1;

    // TODO(bug 001) 填写m_domainId的正确值
    // 目前m_domainId硬编码为1，需要进一步确认是否正确
    tempMAT1.m_domainId = 1;

    // 记录哪些属性为空，默认所有属性都不为空
    WhichEnpty whichIsEmpty = NO_EMPTY;

    // 初始化当前处理的字符串条目的ID
    int curIDKey = 1;

    // 遍历所有分割后的条目信息
    for (auto curStrKey : dividedEntryInfo)
    {
        // 判断当前条目是否为空（即是否全为空格）
        bool const isEmpty = is_all_space (curStrKey);

        // 如果当前条目为空，则记录对应的缺失项
        if (isEmpty)
        {
            switch (curIDKey)
            {
            case MAT1KEY_E:
                whichIsEmpty = static_cast<WhichEnpty> (whichIsEmpty + E_EMPTY);  // E 为空
                break;
            case MAT1KEY_NU:
                whichIsEmpty = static_cast<WhichEnpty> (whichIsEmpty + U_EMPTY);  // NU 为空
                break;
            case MAT1KEY_G:
                whichIsEmpty = static_cast<WhichEnpty> (whichIsEmpty + G_EMPTY);  // G 为空
                break;
            default:
                break;
            }
            curIDKey++;
            continue;
        }

        // 根据条目ID，将解析后的数值存入对应的MAT1字段
        switch (curIDKey)
        {
        case MAT1KEY_MID:
            tempMAT1.m_id = convertToI64 (curStrKey);
            break;
        case MAT1KEY_E:
            tempMAT1.m_E = convertToReal (curStrKey);
            break;
        case MAT1KEY_G:
            tempMAT1.m_G = convertToReal (curStrKey);
            break;
        case MAT1KEY_NU:
            tempMAT1.m_nu = convertToReal (curStrKey);
            break;
        case MAT1KEY_RHO:
            tempMAT1.m_rho = convertToReal (curStrKey);
            break;
        case MAT1KEY_A:
            tempMAT1.m_A = convertToReal (curStrKey);
            break;
        case MAT1KEY_TREF:
            tempMAT1.m_tref = convertToReal (curStrKey);
            break;
        case MAT1KEY_GE:
            tempMAT1.m_ge = convertToReal (curStrKey);
            break;
        case MAT1KEY_ST:
            tempMAT1.m_ST = convertToReal (curStrKey);
            break;
        case MAT1KEY_SC:
            tempMAT1.m_SC = convertToReal (curStrKey);
            break;
        case MAT1KEY_SS:
            tempMAT1.m_SS = convertToReal (curStrKey);
            break;
        default:
            break;
        }
        curIDKey++;
    }

    // 根据缺失项的情况计算缺少的值
    switch (whichIsEmpty)
    {
    case G_EMPTY:
        // 如果G为空，根据E和NU计算G
        tempMAT1.m_G = tempMAT1.m_E / (2 + 2 * tempMAT1.m_nu);
        break;
    case U_EMPTY:
        // 如果NU为空，根据E和G计算NU
        tempMAT1.m_nu = tempMAT1.m_E / tempMAT1.m_G / 2 - 1;
        break;
    case E_EMPTY:
        // 如果E为空，根据G和NU计算E
        tempMAT1.m_E = tempMAT1.m_G * (2 + 2 * tempMAT1.m_nu);
        break;
    case NO_EMPTY:
        // 所有值都不为空，无需额外计算
    case EU_EMPTY:
    case GU_EMPTY:
        // 默认处理EU_EMPTY和GU_EMPTY时，保持值为0
        break;
    default:
        // 如果E和G都为空，抛出异常
        throw std::runtime_error ("MAT1Parser: E and G cannot both be blank");
    }

    // 将解析后的MAT1数据通过数据库服务工厂的IsotropicMaterial服务添加到数据库中
    return dbServiceFactory->get<IIsotropicMaterialService> ()->Add (tempMAT1);
}